GameTreeTestCase = TestCase("GameTreeTestCase");

var GAME_STATE_MANAGER = new GameStateManager();

GameTreeTestCase.prototype.testCreateTree1 = function() {
	var player1 = new PlayerFactory().createPlayerOne(PlayerOwner.CPU);
	var player2 = player1.opponent;	
	
	var rootBoard = new Board(3, 3, 3);
	rootBoard.move(player1, 0, 0); rootBoard.move(player2, 1, 0); rootBoard.move(player1, 2, 0);
	rootBoard.move(player2, 0, 1); rootBoard.move(player1, 1, 1); rootBoard.move(player2, 2, 1);
	rootBoard.move(player2, 0, 2); rootBoard.move(player1, 1, 2);		
	
	var rootGameState = new GameState(rootBoard, PlayerStatus.NONE, player1);
	var rootNode = new GameStateTreeNode(rootGameState);
	
	var gameStatesTree = new GameStatesTree(rootNode, GAME_STATE_MANAGER);
	gameStatesTree.createTree();
	
	var reportedRootNode = gameStatesTree.getRootNode();
	assertEquals(1, reportedRootNode.childNodes.length);
	
	var childNode = reportedRootNode.childNodes[0];
	assertEquals(TokenType.X, childNode.gameState.board.getTokenAt(2,2));
	assertEquals(PlayerStatus.PLAYER_ONE_WIN, childNode.gameState.playerStatus);
	assertEquals(TokenType.O, childNode.gameState.playerToMove.playerTokenType);		
};

GameTreeTestCase.prototype.testCreateTree2 = function() {
	var player1 = new PlayerFactory().createPlayerOne(PlayerOwner.CPU);
	var player2 = player1.opponent;	
	
	var rootBoard = new Board(3, 3, 3);
	rootBoard.move(player1, 0, 0); rootBoard.move(player2, 1, 0); rootBoard.move(player1, 2, 0);
	rootBoard.move(player2, 0, 1); rootBoard.move(player2, 1, 1); rootBoard.move(player1, 2, 1);
								   rootBoard.move(player1, 1, 2);		
	
	var rootGameState = new GameState(rootBoard, PlayerStatus.NONE, player2);
	var rootNode = new GameStateTreeNode(rootGameState);
	
	var gameStatesTree = new GameStatesTree(rootNode, GAME_STATE_MANAGER);
	gameStatesTree.createTree();
	
	var reportedRootNode = gameStatesTree.getRootNode();
	assertEquals(2, reportedRootNode.childNodes.length);
	assertEquals(1, reportedRootNode.childNodes[0].childNodes.length);
	assertEquals(1, reportedRootNode.childNodes[1].childNodes.length);
	
	assertEquals(PlayerStatus.PLAYER_ONE_WIN, 
			reportedRootNode.childNodes[0].childNodes[0].gameState.playerStatus);
	assertEquals(PlayerStatus.DRAW, 
			reportedRootNode.childNodes[1].childNodes[0].gameState.playerStatus);
};

GameTreeTestCase.prototype.testCreateTree3 = function() {
	var player1 = new PlayerFactory().createPlayerOne(PlayerOwner.CPU);
	var player2 = player1.opponent;	
	
	var rootBoard = new Board(3, 3, 3);
	rootBoard.move(player1, 0, 0); rootBoard.move(player2, 1, 0); rootBoard.move(player1, 2, 0);
	rootBoard.move(player2, 0, 1); rootBoard.move(player2, 1, 1); 	
	
	var rootGameState = new GameState(rootBoard, PlayerStatus.NONE, player2);
	var rootNode = new GameStateTreeNode(rootGameState);
	
	var gameStatesTree = new GameStatesTree(rootNode, GAME_STATE_MANAGER);
	var st = new Date().getTime();
	gameStatesTree.createTree();
	var et = new Date().getTime();
	
	DEBUG_CONSOLE.toConsole("gameStatesTree.createTree() time starting with 5 tokens on 3x3 board: "+(et-st)+" ms. Nodes: " + gameStatesTree.nodesCount);
};

GameTreeTestCase.prototype.testCreateTree4 = function() {
	var player1 = new PlayerFactory().createPlayerOne(PlayerOwner.CPU);
	var player2 = player1.opponent;	
	
	var rootBoard = new Board(3, 3, 3);
	rootBoard.move(player2, 1, 1); 	
	
	var rootGameState = new GameState(rootBoard, PlayerStatus.NONE, player2);
	var rootNode = new GameStateTreeNode(rootGameState);
	
	var gameStatesTree = new GameStatesTree(rootNode,GAME_STATE_MANAGER);
	var st = new Date().getTime();
	gameStatesTree.createTree();
	var et = new Date().getTime();
	
	DEBUG_CONSOLE.toConsole("gameStatesTree.createTree() time starting with 1 tokens on 3x3 board: "+(et-st)+" ms. Nodes: " + gameStatesTree.nodesCount);
};

GameTreeTestCase.prototype.testCreateTree5 = function() {
	var player1 = new PlayerFactory().createPlayerOne(PlayerOwner.CPU);
	var player2 = player1.opponent;	
	
	var rootBoard = new Board(3, 3, 3);
	
	var rootGameState = new GameState(rootBoard, PlayerStatus.NONE, player1);
	var rootNode = new GameStateTreeNode(rootGameState);
	
	var gameStatesTree = new GameStatesTree(rootNode, GAME_STATE_MANAGER);
	var st = new Date().getTime();
	gameStatesTree.createTree();
	var et = new Date().getTime();
	
	var intermediateNodesTotalCount = 0;
	for(var i = 0; i < gameStatesTree.intermediateStatesToTreeDepth.length; i++) {
		//DEBUG_CONSOLE.toConsole("Depth = " + i + " intermediate nodes count = " + gameStatesTree.intermediateStatesToTreeDepth[i].length);
		intermediateNodesTotalCount += gameStatesTree.intermediateStatesToTreeDepth[i].length;
	}
	//DEBUG_CONSOLE.toConsole("intermediateNodesTotalCount = " + intermediateNodesTotalCount);
	
	DEBUG_CONSOLE.toConsole("gameStatesTree.createTree() time starting with 0 tokens on 3x3 board: "+(et-st)+" ms. Nodes: " + gameStatesTree.nodesCount);
};

GameTreeTestCase.prototype.testCreateTree6 = function() {
	var player1 = new PlayerFactory().createPlayerOne(PlayerOwner.CPU);
	var player2 = player1.opponent;	
	
	var rootBoard = new Board(4, 3, 3);
	
	var rootGameState = new GameState(rootBoard, PlayerStatus.NONE, player1);
	var rootNode = new GameStateTreeNode(rootGameState);
	
	var gameStatesTree = new GameStatesTree(rootNode, GAME_STATE_MANAGER);
	var st = new Date().getTime();
	gameStatesTree.createTree();
	var et = new Date().getTime();
	
	DEBUG_CONSOLE.toConsole("gameStatesTree.createTree() time starting with 0 tokens on 4x3 board: "+(et-st)+" ms. Nodes: " + gameStatesTree.nodesCount);
};

/*
 * will most likely run out of resources and hang the browser
 */
//GameTreeTestCase.prototype.testCreateTree62 = function() {
//	var player1 = new PlayerFactory().createPlayerOne(PlayerOwner.CPU);
//	var player2 = player1.opponent;	
//	
//	var rootBoard = new Board(4, 4, 3);
//	
//	var rootGameState = new GameState(rootBoard, PlayerStatus.NONE, player1);
//	var rootNode = new GameStateTreeNode(rootGameState);
//	
//	var gameStatesTree = new GameStatesTree(rootNode, GAME_STATE_MANAGER);
//	var st = new Date().getTime();
//	gameStatesTree.createTree();
//	var et = new Date().getTime();
//	
//	DEBUG_CONSOLE.toConsole("gameStatesTree.createTree() time starting with 0 tokens on 4x4 board: "+(et-st)+" ms. Nodes: " + gameStatesTree.nodesCount);
//};

GameTreeTestCase.prototype.testCreateTree7 = function() {
	var player1 = new PlayerFactory().createPlayerOne(PlayerOwner.CPU);
	var player2 = player1.opponent;	
	
	var rootBoard = new Board(3, 3, 3);
	/*
	XOX
	OXO
	OX_
	 */
	rootBoard.move(player1, 0, 0); rootBoard.move(player2, 1, 0); rootBoard.move(player1, 2, 0);
	rootBoard.move(player2, 0, 1); rootBoard.move(player1, 1, 1); rootBoard.move(player2, 2, 1);
	rootBoard.move(player2, 0, 2); rootBoard.move(player1, 1, 2);
	
	var rootGameState = new GameState(rootBoard, PlayerStatus.NONE, player1);
	var rootNode = new GameStateTreeNode(rootGameState);
	
	var gameStatesTree = new GameStatesTree(rootNode, GAME_STATE_MANAGER);
	gameStatesTree.createTree();
	
	var generatedRootNode = gameStatesTree.getRootNode();
	
	assertEquals(1, generatedRootNode.childNodes[0].score);
};

GameTreeTestCase.prototype.testCreateTree8 = function() {
	var player1 = new PlayerFactory().createPlayerOne(PlayerOwner.HUMAN);
	var player2 = player1.opponent;	
	
	var rootBoard = new Board(3, 3, 3);
	/*
	XOX
	OXO
	OX_
	 */
	rootBoard.move(player1, 0, 0); rootBoard.move(player2, 1, 0); rootBoard.move(player1, 2, 0);
	rootBoard.move(player2, 0, 1); rootBoard.move(player1, 1, 1); rootBoard.move(player2, 2, 1);
	rootBoard.move(player2, 0, 2); rootBoard.move(player1, 1, 2);
	
	var rootGameState = new GameState(rootBoard, PlayerStatus.NONE, player1);
	var rootNode = new GameStateTreeNode(rootGameState);
	
	var gameStatesTree = new GameStatesTree(rootNode, GAME_STATE_MANAGER);
	gameStatesTree.createTree();
	
	var generatedRootNode = gameStatesTree.getRootNode();
	
	assertEquals(-1, generatedRootNode.childNodes[0].score);
};

GameTreeTestCase.prototype.testCreateTree9 = function() {
	var player1 = new PlayerFactory().createPlayerOne(PlayerOwner.CPU);
	var player2 = player1.opponent;	
	
	var rootBoard = new Board(3, 3, 3);
	/*
	XOX
	__O
	OX_
	 */
	rootBoard.move(player1, 0, 0); rootBoard.move(player2, 1, 0); rootBoard.move(player1, 2, 0);
																  rootBoard.move(player2, 2, 1);
	rootBoard.move(player2, 0, 2); rootBoard.move(player1, 1, 2);
	
	var rootGameState = new GameState(rootBoard, PlayerStatus.NONE, player1);
	var rootNode = new GameStateTreeNode(rootGameState);
	
	var gameStatesTree = new GameStatesTree(rootNode, GAME_STATE_MANAGER);
	gameStatesTree.createTree();
	
	var generatedRootNode = gameStatesTree.getRootNode();
	
	assertEquals(1, gameStatesTree.intermediateStatesToTreeDepth[0].length);
	assertEquals(3, gameStatesTree.intermediateStatesToTreeDepth[1].length);
	assertEquals(6, gameStatesTree.intermediateStatesToTreeDepth[2].length);
	assertEquals(0, gameStatesTree.intermediateStatesToTreeDepth[3].length);
	assertEquals(0, gameStatesTree.intermediateStatesToTreeDepth[4].length);
	
	var zeroScoreCount = 0;
	var oneScoreCount = 0;
	
	var self = this;
	
	gameStatesTree.intermediateStatesToTreeDepth[2].forEach(function(itermNode) {
		assertEquals(1, itermNode.childNodes.length);
		if(itermNode.childNodes[0].score==0) {
			zeroScoreCount++;
		}
		if(itermNode.childNodes[0].score==1) {
			oneScoreCount++;
		}
	});		
	assertEquals(4, zeroScoreCount);
	assertEquals(2, oneScoreCount);
	
};

GameTreeTestCase.prototype.testScoreIntermediateStates1 = function() {
	var player1 = new PlayerFactory().createPlayerOne(PlayerOwner.CPU);
	var player2 = player1.opponent;	
	
	var rootBoard = new Board(3, 3, 3);
	/*
	XOX
	__O
	OX_
	 */
	rootBoard.move(player1, 0, 0); rootBoard.move(player2, 1, 0); rootBoard.move(player1, 2, 0);
																  rootBoard.move(player2, 2, 1);
	rootBoard.move(player2, 0, 2); rootBoard.move(player1, 1, 2);
	
	var rootGameState = new GameState(rootBoard, PlayerStatus.NONE, player1);
	var rootNode = new GameStateTreeNode(rootGameState);
	
	var gameStatesTree = new GameStatesTree(rootNode, GAME_STATE_MANAGER);
	gameStatesTree.createTree();
	gameStatesTree.scoreIntermediateStates();
	
	var generatedRootNode = gameStatesTree.getRootNode();
	
	assertEquals(1, gameStatesTree.intermediateStatesToTreeDepth[0].length);
	assertEquals(3, gameStatesTree.intermediateStatesToTreeDepth[1].length);
	assertEquals(6, gameStatesTree.intermediateStatesToTreeDepth[2].length);
	assertEquals(0, gameStatesTree.intermediateStatesToTreeDepth[3].length);
	assertEquals(0, gameStatesTree.intermediateStatesToTreeDepth[4].length);
	
	var self = this;
	
	var zeroScoreCount = 0;
	var oneScoreCount = 0;		
			
	gameStatesTree.intermediateStatesToTreeDepth[2].forEach(function(itermNode) {
		assertEquals(1, itermNode.childNodes.length);
		if(itermNode.childNodes[0].score==0) {
			zeroScoreCount++;
		}
		if(itermNode.childNodes[0].score==1) {
			oneScoreCount++;
		}
	});		
	assertEquals(4, zeroScoreCount);
	assertEquals(2, oneScoreCount);
	
	zeroScoreCount = 0;
	oneScoreCount = 0;		
			
	gameStatesTree.intermediateStatesToTreeDepth[2].forEach(function(itermNode) {
		if(itermNode.score==0) {
			zeroScoreCount++;
		}
		if(itermNode.score==1) {
			oneScoreCount++;
		}
	});		
	assertEquals(4, zeroScoreCount);
	assertEquals(2, oneScoreCount);
	
	zeroScoreCount = 0;
	oneScoreCount = 0;		
			
	gameStatesTree.intermediateStatesToTreeDepth[1].forEach(function(itermNode) {
		if(itermNode.score==0) {
			zeroScoreCount++;
		}
		if(itermNode.score==1) {
			oneScoreCount++;
		}
	});		
	assertEquals(3, zeroScoreCount);
	
	assertEquals(0, generatedRootNode.score);
	
};

GameTreeTestCase.prototype.testPlay1 = function() {
	var player1 = new PlayerFactory().createPlayerOne(PlayerOwner.CPU);
	var player2 = player1.opponent;	
	
	var rootBoard = new Board(3, 3, 3);
			
	var rootGameState = new GameState(rootBoard, PlayerStatus.NONE, player1);
	var rootNode = new GameStateTreeNode(rootGameState);
	
	var gameStatesTree = new GameStatesTree(rootNode, GAME_STATE_MANAGER);
	gameStatesTree.createTree();
	gameStatesTree.scoreIntermediateStates();
	
	var generatedRootNode = gameStatesTree.getRootNode();
	
//	DEBUG_CONSOLE.toConsole("root node: ");
//	DEBUG_CONSOLE.toConsole(generatedRootNode.gameState.board.toString("\n"));
	
	var move1Node = null;
	var score = -1;
	for(var i = 0; i<generatedRootNode.childNodes.length;i++) {
		if(generatedRootNode.childNodes[i].score > score) {
			move1Node = generatedRootNode.childNodes[i];
			score = move1Node.score;
		}
	}
	
//	DEBUG_CONSOLE.toConsole("mode 1 node: ");
//	DEBUG_CONSOLE.toConsole(move1Node.gameState.board.toString("\n"));
	
	var move2Node = null;
	for(var i = 0; i<move1Node.childNodes.length;i++) {
		if(move1Node.childNodes[i].hash === "120000000") {
			move2Node = move1Node.childNodes[i];
			break;
		}
	}
	
//	DEBUG_CONSOLE.toConsole("mode 2 node: ");
//	DEBUG_CONSOLE.toConsole(move2Node.gameState.board.toString("\n"));
	
	var move3Node = null;
	score = -1;
	for(var i = 0; i<move2Node.childNodes.length;i++) {
		if(move2Node.childNodes[i].score > score) {
			move3Node = move2Node.childNodes[i];
			score = move2Node.score;
		}
	}
	
//	DEBUG_CONSOLE.toConsole("mode 3 node: ");
//	DEBUG_CONSOLE.toConsole(move3Node.gameState.board.toString("\n"));
	
	var move4Node = null;
	for(var i = 0; i<move3Node.childNodes.length;i++) {
		if(move3Node.childNodes[i].hash === "121020000") {
			move4Node = move3Node.childNodes[i];
			break;
		}
	}
	
//	DEBUG_CONSOLE.toConsole("mode 4 node: ");
//	DEBUG_CONSOLE.toConsole(move4Node.gameState.board.toString("\n"));
	
	var move5Node = null;
	score = -1;
	for(var i = 0; i<move4Node.childNodes.length;i++) {
		if(move4Node.childNodes[i].score > score) {
			move5Node = move4Node.childNodes[i];
			score = move5Node.score;
		}
	}
	
//	DEBUG_CONSOLE.toConsole("mode 5 node: ");
//	DEBUG_CONSOLE.toConsole(move5Node.gameState.board.toString("\n"));
	
	var move6Node = null;
	for(var i = 0; i<move5Node.childNodes.length;i++) {
		if(move5Node.childNodes[i].hash === "121022010") {
			move6Node = move5Node.childNodes[i];
			break;
		}
	}
	
//	DEBUG_CONSOLE.toConsole("mode 6 node: ");
//	DEBUG_CONSOLE.toConsole(move6Node.gameState.board.toString("\n"));
	
	var move7Node = null;
	score = -1;
	for(var i = 0; i<move6Node.childNodes.length;i++) {
		if(move6Node.childNodes[i].score > score) {
			move7Node = move6Node.childNodes[i];
			score = move7Node.score;
		}
	}
	
//	DEBUG_CONSOLE.toConsole("mode 7 node: ");
//	DEBUG_CONSOLE.toConsole(move7Node.gameState.board.toString("\n"));
	
	var move8Node = null;
	for(var i = 0; i<move7Node.childNodes.length;i++) {
		if(move7Node.childNodes[i].hash === "121122012") {
			move8Node = move7Node.childNodes[i];
			break;
		}
	}
	
//	DEBUG_CONSOLE.toConsole("mode 8 node: ");
//	DEBUG_CONSOLE.toConsole(move8Node.gameState.board.toString("\n"));
	
	var move9Node = null;
	score = -1;
	for(var i = 0; i<move8Node.childNodes.length;i++) {
		if(move6Node.childNodes[i].score > score) {
			move9Node = move8Node.childNodes[i];
			score = move9Node.score;
		}
	}
	
//	DEBUG_CONSOLE.toConsole("mode 9 node: ");
//	DEBUG_CONSOLE.toConsole(move9Node.gameState.board.toString("\n"));	
//	DEBUG_CONSOLE.toConsole("Winning player: "+move9Node.gameState.playerStatus);
	
	assertEquals("XOX\nXOO\nXXO\n", move9Node.gameState.board.toString("\n"));
	assertEquals(1, move9Node.gameState.playerStatus);
};